#include "http_connection.h"
#include "../log.h"
#include "http_parser.h"
#include <sys/socket.h>

namespace framework
{
namespace http
{

static framework::Logger::ptr g_logger = FRAMEWORK_LOG_NAME("system");

std::string HttpResult::errorNumtoString(Error result) const
{
    switch (result)
    {
#define XX(name)    \
    case Error::name: return #name;

    XX(OK);                    
    XX(INVALID_URL);           
    XX(INVALID_HOST);         
    XX(CONNECT_FAIL);          
    XX(SEND_CLOSE_BY_PEER);   
    XX(SEND_SOCKET_ERROR);     
    XX(TIMEOUT);               
    XX(CREATE_SOCKET_ERROR);  
    XX(POOL_GET_CONNECTION);   
    XX(POOL_INVALID_CONNECTION);

#undef XX
    default:
        return "result error";
    }
}

std::string HttpResult::toString() const
{
    std::stringstream ss;
    ss << "[HttpResult result=" << errorNumtoString(result)
       << " error=" << error
       << " response=" << (response ? response->toString() : "nullptr")
       << "]";
    return ss.str();
}


//===============================================================================


HttpConnection::HttpConnection(Socket::ptr sock, bool owner)
:SocketStream(sock, owner)
,m_createTime(framework::GetCurrentMS())
{}

HttpConnection::~HttpConnection()
{
    FRAMEWORK_LOG_DEBUG(g_logger) << "HttpConnection::~HttpConnection";
}

//接收HTTP响应
HttpResponse::ptr HttpConnection::recvResponse()
{
    //http响应解析类
    HttpResponseParser::ptr parser(new HttpResponseParser);
    //获取协议解析的缓存最大大小
    uint64_t buffer_size = HttpResponseParser::GetHttpRequestBufferSize();
    std::shared_ptr<char> buffer(new char[buffer_size + 1],[](char* ptr){
        delete[] ptr;
    });
    char* data = buffer.get();
    int offset = 0; //当前还没有解析完成的长度
    while(true) //解析报文的头部信息
    {
        int len = read(data + offset, buffer_size - offset);
        if(len < 0)
        {
            close();
            return nullptr;
        }
        len += offset;
        data[len] = '\0';
        size_t nparse = parser->execute(data, len, false);
        if(parser->hasError())
        {
            close();
            return nullptr;
        }
        offset = len - nparse;
        if(offset >= (int)buffer_size)
        {
            close();
            return nullptr;
        }
        if(parser->isFinished())
        {
            break;
        }
    }

    //获取http响应结构体
    auto& client_parser = parser->getParser();
    std::string body;
    if(client_parser.chunked)   //如果报文存在分段
    {
        int len = offset; //当前data中剩余数据的数量
        do
        {
            bool begin = true;
            do
            {
                //!begin 表示第一个数据块中还有剩余的数据没有解析完，就先解析这些数据
                //len == 0 表示如果现有数据已经解析完了，就继续读数据
                if(!begin || len == 0) 
                {
                    int rt = read(data + len,  buffer_size - len);
                    if(rt <= 0)
                    {
                        close();
                        FRAMEWORK_LOG_ERROR(g_logger) << "server close";
                        return nullptr;
                    }
                    len += rt;
                }
                data[len] = '\0';
                size_t nparse = parser->execute(data, len, true);   //报文分片时，每次都要从新解析报文头
                if(parser->hasError())
                {
                    close();
                    FRAMEWORK_LOG_ERROR(g_logger) << "execute error";
                    return nullptr;
                }
                len -= nparse;
                if(len >= (int)buffer_size) //没有解析成功的数据超过读缓冲区大小
                {
                    close();
                    FRAMEWORK_LOG_ERROR(g_logger) << "execute error";
                    return nullptr;
                }
                begin = false;
            } while (!parser->isFinished());
            FRAMEWORK_LOG_DEBUG(g_logger) << "content_len = " << client_parser.content_len << "\tlen = " << len;

            //这里的2表示获取client_parser.content_len后面的一个换行符 \n\r
            if(client_parser.content_len + 2 <= len)    //如果存在还没有解析的数据
            {
                body.append(data, client_parser.content_len);//将解析完成的数据拼接到body末尾
                memmove(data, data + client_parser.content_len + 2, //将已经解析完成的数据覆盖掉
                    len - client_parser.content_len - 2);
                len -= client_parser.content_len + 2;   //剩余还没有解析数据的长度
            }
            else
            {
                body.append(data, len);
                int left = client_parser.content_len - len + 2;
                while(left > 0)    //还有消息体没有读完
                {
                    //读完剩余的消息体
                    int rt = read(data, left > (int)buffer_size ? (int)buffer_size : left);
                    if(rt <= 0)
                    {
                        close();
                        FRAMEWORK_LOG_ERROR(g_logger) << "server close";
                        return nullptr;
                    }
                    body.append(data, rt);
                    left -= rt;
                }
                body.resize(body.size() - 2);
                len = 0;
            }
            
        } while (!client_parser.chunks_done);
        parser->getData()->setBody(body);
    }
    else    //如果报文没有分段
    {
        int64_t length = parser->getContentLength();
        if(length > 0) {
            body.resize(length);

            int len = 0;
            if(length >= offset) {
                memcpy(&body[0], data, offset);
                len = offset;
            } else {
                memcpy(&body[0], data, length);
                len = length;
            }
            length -= offset;
            if(length > 0) {
                if(readFixSize(&body[len], length) <= 0) {
                    close();
                    return nullptr;
                }
            }
            parser->getData()->setBody(body);
        }
    }

    // if(!body.empty())
    // {
    //     auto content_encoding = parser->getData()->getHeader("content-encoding");
    //     FRAMEWORK_LOG_DEBUG(g_logger) << "content_encoding: " << content_encoding
    //         << " size = " << body.size();
    // }

    return parser->getData();
}

//发送HTTP请求
int HttpConnection::sendRequest(HttpRequest::ptr rsp)
{
    std::stringstream ss;
    ss << *rsp;
    std::string data = ss.str();
    return writeFixSize(data.c_str(), data.size());
}

//发送HTTP的GET请求
HttpResult::ptr HttpConnection::DoGet(const std::string& url
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    Uri::ptr uri = Uri::Create(url);
    if(!uri)
    {
        return std::make_shared<HttpResult>(HttpResult::Error::INVALID_URL, 
        nullptr, "invalid url: " + url);
    }
    return DoGet(uri, timeout_ms, headers, body);
}

//发送HTTP的GET请求
HttpResult::ptr HttpConnection::DoGet(Uri::ptr uri
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    return DoRequest(HttpMetHod::GET, uri, timeout_ms, headers, body);
}

//发送HTTP的POST请求
HttpResult::ptr HttpConnection::DoPost(const std::string& url
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    Uri::ptr uri = Uri::Create(url);
    if(!uri)
    {
        return std::make_shared<HttpResult>(HttpResult::Error::INVALID_URL, 
        nullptr, "invalid url: " + url);
    }
    return DoPost(uri, timeout_ms, headers, body);
}

//发送HTTP的POST请求
HttpResult::ptr HttpConnection::DoPost(Uri::ptr uri
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    return DoRequest(HttpMetHod::POST, uri, timeout_ms, headers, body);
}

//发送HTTP请求
HttpResult::ptr HttpConnection::DoRequest(HttpMetHod method
                        , const std::string& url
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    Uri::ptr uri = Uri::Create(url);
    if(!uri)
    {
        return std::make_shared<HttpResult>(HttpResult::Error::INVALID_URL, 
        nullptr, "invalid url: " + url);
    }
    return DoRequest(method, uri, timeout_ms, headers, body);
}

//发送HTTP请求
HttpResult::ptr HttpConnection::DoRequest(HttpMetHod method
                        , Uri::ptr uri
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    HttpRequest::ptr req = std::make_shared<HttpRequest>();
    req->setPath(uri->getPath());
    req->setQuery(uri->getQuery());
    req->setFragment(uri->getFragment());
    req->setMethod(method);
    bool has_host = false;

    for(auto& t: headers)
    {
        //设置是否保持链接
        if(strcasecmp(t.first.c_str(), "connection") == 0)
        {
            if(strcasecmp(t.second.c_str(), "keep-alive") == 0)
            {
                req->setClose(false);
            }
            continue;
        }

        //判断headers中有没有设置host
        if(!has_host && strcasecmp(t.first.c_str(), "host") == 0) 
        {
            has_host = !t.second.empty();
        }

        req->setHeader(t.first, t.second);
    }
    if(!has_host)   //如果headers中没有设置host 就使用uri中的host
    {
        req->setHeader("Host", uri->getHost());
    }
    req->setBody(body);
    return DoRequest(std::move(req), uri, timeout_ms);
}

//发送HTTP请求
HttpResult::ptr HttpConnection::DoRequest(HttpRequest::ptr req
                        , Uri::ptr uri
                        , uint64_t timeout_ms)
{
    bool is_ssl = uri->getScheme() == "https";

    //获取addr
    Address::ptr addr = uri->createAddress();
    if(!addr)
    {
        return std::make_shared<HttpResult>(HttpResult::Error::INVALID_HOST
            , nullptr, "invalid host: " + uri->getHost());
    }

    //创建sock
    Socket::ptr sock = is_ssl ? SSLSocket::CreateTCP(addr) : Socket::CreateTCP(addr);
    if(!sock) 
    {
        return std::make_shared<HttpResult>(HttpResult::Error::CREATE_SOCKET_ERROR
                , nullptr, "create socket fail: " + addr->toString()
                        + " errno=" + std::to_string(errno)
                        + " errstr=" + std::string(strerror(errno)));
    }

    //连接服务器
    if(!sock->connect(addr)) 
    {
        return std::make_shared<HttpResult>(HttpResult::Error::CONNECT_FAIL
                , nullptr, "connect fail: " + addr->toString());
    }
    //设置超时时间
    sock->setRecvTimeout(timeout_ms);

    //创建客户端类
    HttpConnection::ptr conn = std::make_shared<HttpConnection>(sock);
    //发送请求
    int rt = conn->sendRequest(req);    
    if(rt == 0)
    {
        return std::make_shared<HttpResult>(HttpResult::Error::SEND_CLOSE_BY_PEER
            , nullptr, "send request closed by peer: " + addr->toString());
    }
    if(rt < 0)
    {
        return std::make_shared<HttpResult>(HttpResult::Error::SEND_SOCKET_ERROR
            , nullptr, "send request socket error errno=" + std::to_string(errno)
            + " errstr=" + std::string(strerror(errno)));
    }

    //接收请求
    auto rsp = conn->recvResponse();
    if(!rsp) {
        return std::make_shared<HttpResult>(HttpResult::Error::TIMEOUT
            , nullptr, "recv response timeout: " + addr->toString()
            + " timeout_ms:" + std::to_string(timeout_ms));
    }

    return std::make_shared<HttpResult>(HttpResult::Error::OK, rsp, "ok");
}

//=====================================================================================


HttpConnectionPool::HttpConnectionPool(const std::string& host
                ,const std::string& vhost
                ,uint32_t port
                ,bool is_https
                ,uint32_t max_size
                ,uint32_t max_alive_time
                ,uint32_t max_request)
:m_host(host)
,m_vhost(vhost)
,m_port(port ? port : (is_https ? 443 : 80))
,m_maxSize(max_size)
,m_maxAliveTime(max_alive_time)
,m_maxRequest(max_request)
,m_isHttps(is_https) {}

//创建连接池
HttpConnectionPool::ptr HttpConnectionPool::Create(const std::string& uri
                            ,const std::string& vhost
                            ,uint32_t max_size
                            ,uint32_t max_alive_time
                            ,uint32_t max_request)
{
    Uri::ptr turi = Uri::Create(uri);
    if(!turi)
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "invalid uri=" << uri;
    }

    return std::make_shared<HttpConnectionPool>(turi->getHost(), vhost, turi->getPort(), 
            turi->getScheme() == "https", max_size, max_alive_time, max_request);
}

//获取连接
HttpConnection::ptr HttpConnectionPool::getConnection()
{
    uint64_t now_ms = framework::GetCurrentMS(); //获取当前时间的毫秒
    std::vector<HttpConnection*> invalid_conns;  //保存要删除的连接
    HttpConnection* ptr = nullptr;
    MutexType::Lock lock(m_mutex);
    while(!m_conns.empty())
    {
        auto conn = *m_conns.begin();   //拿到连接池第一个元素
        m_conns.pop_front();
        if(!conn->isConnected())    //如果当前连接已经断开，则从连接池删除
        {
            invalid_conns.push_back(conn);
            continue;
        }
        if(now_ms > (conn->m_createTime + m_maxAliveTime)) //如果连接已经超时，则从连接池删除
        {
            invalid_conns.push_back(conn);
            continue;
        }
        ptr = conn;  //找到第一个正常的连接
        break;
    }
    lock.unlock();

    for(auto t: invalid_conns)  //删除连接
    {
        delete t;
    }
    m_total -= invalid_conns.size();

    if(!ptr) //如果没有找到可用连接，就创建一个新连接
    {
        IPAddress::ptr addr = Address::LookupAnyIPAddress(m_host);
        if(!addr) {
            FRAMEWORK_LOG_ERROR(g_logger) << "get addr fail: " << m_host;
            return nullptr;
        }
        addr->setPort(m_port);
        Socket::ptr sock = m_isHttps ? SSLSocket::CreateTCP(addr) : Socket::CreateTCP(addr);
        if(!sock)
        {
            FRAMEWORK_LOG_ERROR(g_logger) << "create sock fail: " << *addr;
            return nullptr;
        }
        if(!sock->connect(addr))
        {
            FRAMEWORK_LOG_ERROR(g_logger) << "sock connect fail: " << *addr;
            return nullptr;
        }

        ptr = new HttpConnection(sock);
        ++m_total;
    }

    //创建智能指针时指定析构函数
    return HttpConnection::ptr(ptr, std::bind(&HttpConnectionPool::ReleasePtr
                            , std::placeholders::_1, this));

    return nullptr;
}

//释放连接 将连接回收到连接池
void HttpConnectionPool::ReleasePtr(HttpConnection* ptr, HttpConnectionPool* pool)
{   
    ++ptr->m_request;       //请求次数+1
    if(!ptr->isConnected()  //连接已断开
        || ((framework::GetCurrentMS() >= ptr->m_createTime + pool->m_maxAliveTime))    //连接已超时
        || (ptr->m_request >= pool->m_maxRequest))  //请求数量过多
    {
        delete ptr;
        --pool->m_total;
        return;
    }

    //如果连接池数量没满，就加回连接池
    MutexType::Lock lock(pool->m_mutex);
    pool->m_conns.push_back(ptr);
}



//发送HTTP的GET请求
HttpResult::ptr HttpConnectionPool::doGet(const std::string& url
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    return doRequest(HttpMetHod::GET, url, timeout_ms, headers, body);
}

//发送HTTP的GET请求
HttpResult::ptr HttpConnectionPool::doGet(Uri::ptr uri
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    //将Uri转为字符串 - 没有获取host
    std::stringstream ss;
    ss << uri->getPath()
       << (uri->getQuery().empty() ? "" : "?")
       << uri->getQuery()
       << (uri->getFragment().empty() ? "" : "#")
       << uri->getFragment();
    
    return doGet(ss.str(), timeout_ms, headers, body);
}

//发送HTTP的POST请求
HttpResult::ptr HttpConnectionPool::doPost(const std::string& url
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    return doRequest(HttpMetHod::POST, url, timeout_ms, headers, body);
}

//发送HTTP的POST请求
HttpResult::ptr HttpConnectionPool::doPost(Uri::ptr uri
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    //将Uri转为字符串 - 没有获取host
    std::stringstream ss;
    ss << uri->getPath()
       << (uri->getQuery().empty() ? "" : "?")
       << uri->getQuery()
       << (uri->getFragment().empty() ? "" : "#")
       << uri->getFragment();
    
    return doPost(ss.str(), timeout_ms, headers, body);
}

//发送HTTP请求
HttpResult::ptr HttpConnectionPool::doRequest(HttpMetHod method
                        , const std::string& url
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    HttpRequest::ptr req = std::make_shared<HttpRequest>();
    req->setPath(url);
    req->setMethod(method);
    req->setClose(false);
    bool has_host = false;
    for(auto& i : headers) {
        if(strcasecmp(i.first.c_str(), "connection") == 0) {
            if(strcasecmp(i.second.c_str(), "keep-alive") == 0) {
                req->setClose(false);
            }
            continue;
        }

        //获取是否有host
        if(!has_host && strcasecmp(i.first.c_str(), "host") == 0) {
            has_host = !i.second.empty();
        }

        req->setHeader(i.first, i.second);
    }
    if(!has_host) {
        if(m_vhost.empty()) {
            req->setHeader("Host", m_host);
        } else {
            req->setHeader("Host", m_vhost);
        }
    }
    req->setBody(body);
    return doRequest(req, timeout_ms);
}

//发送HTTP请求
HttpResult::ptr HttpConnectionPool::doRequest(HttpMetHod method
                        , Uri::ptr uri
                        , uint64_t timeout_ms
                        , const std::map<std::string, std::string>& headers
                        , const std::string& body)
{
    //将Uri转为字符串 - 没有获取host
    std::stringstream ss;
    ss << uri->getPath()
       << (uri->getQuery().empty() ? "" : "?")
       << uri->getQuery()
       << (uri->getFragment().empty() ? "" : "#")
       << uri->getFragment();
    
    return doRequest(method, ss.str(), timeout_ms, headers, body);
}

//发送HTTP请求
HttpResult::ptr HttpConnectionPool::doRequest(HttpRequest::ptr req
                        , uint64_t timeout_ms)
{
    //从线程池中获取连接
    auto conn = getConnection();
    if(!conn) {
        return std::make_shared<HttpResult>(HttpResult::Error::POOL_GET_CONNECTION
                , nullptr, "pool host:" + m_host + " port:" + std::to_string(m_port));
    }

    auto sock = conn->getSocket();
    if(!sock) {
        return std::make_shared<HttpResult>(HttpResult::Error::POOL_INVALID_CONNECTION
                , nullptr, "pool host:" + m_host + " port:" + std::to_string(m_port));
    }
    sock->setRecvTimeout(timeout_ms);

    //发送请求
    int rt = conn->sendRequest(req);
    if(rt == 0) {
        return std::make_shared<HttpResult>(HttpResult::Error::SEND_CLOSE_BY_PEER
                , nullptr, "send request closed by peer: " + sock->getRemoteAddress()->toString());
    }
    if(rt < 0) {
        return std::make_shared<HttpResult>(HttpResult::Error::SEND_SOCKET_ERROR
                    , nullptr, "send request socket error errno=" + std::to_string(errno)
                    + " errstr=" + std::string(strerror(errno)));
    }

    //接收响应
    auto rsp = conn->recvResponse();
    if(!rsp) {
        return std::make_shared<HttpResult>(HttpResult::Error::TIMEOUT
                    , nullptr, "recv response timeout: " + sock->getRemoteAddress()->toString()
                    + " timeout_ms:" + std::to_string(timeout_ms));
    }
    return std::make_shared<HttpResult>(HttpResult::Error::OK, rsp, "ok");
}

} // namespace http  
} // namespace framework
